package cn.yuysaln.domain.strategy.service.rule.tree.factory.engine;

import cn.yuysaln.domain.strategy.model.valobj.RuleLogicCheckTypeVO;
import cn.yuysaln.domain.strategy.model.valobj.RuleTreeNodeLineVO;
import cn.yuysaln.domain.strategy.model.valobj.RuleTreeNodeVO;
import cn.yuysaln.domain.strategy.model.valobj.RuleTreeVO;
import cn.yuysaln.domain.strategy.service.rule.tree.ILogicTree;
import cn.yuysaln.domain.strategy.service.rule.tree.factory.DefaultTreeFactory;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.List;
import java.util.Map;
@Slf4j
public class DecisionTreeEngine implements IDecisionTreeEngine{
    /** 所有的规则树节点实例Map */
    private final Map<String , ILogicTree> logicTreeNodeGroup;
    /** 规则树入口 */
    private final RuleTreeVO ruleTreeVO;
    public DecisionTreeEngine(Map<String, ILogicTree> logicTreeNodeGroup, RuleTreeVO ruleTreeVO) {
        this.logicTreeNodeGroup = logicTreeNodeGroup;
        this.ruleTreeVO = ruleTreeVO;
    }

    /**
     * 遍历并执行规则树
     * @param userId
     * @param strategyId
     * @param awardId 初步获得的奖品ID
     * @return
     */
    @Override
    public DefaultTreeFactory.StrategyAwardVO process(String userId, Long strategyId, Integer awardId, Date endDateTime) {
        DefaultTreeFactory.StrategyAwardVO strategyAwardData = null;

        //根节点的名称
        String nextNodeName = ruleTreeVO.getTreeRootRuleNode();

        //所有VO节点的Map集合
        Map<String, RuleTreeNodeVO> treeNodeMap = ruleTreeVO.getTreeNodeMap();
        //从集合中拿到根节点的VO
        RuleTreeNodeVO ruleTreeNodeVO = treeNodeMap.get(nextNodeName);

        //开始遍历规则树
        while (null != nextNodeName){
            //VO中的key找到实例     如：rule_lock   ->   RuleLockLogicTreeNode
            ILogicTree logicTreeNode = logicTreeNodeGroup.get(ruleTreeNodeVO.getRuleKey());
            String ruleValue = ruleTreeNodeVO.getRuleValue();
            //执行实例中的具体过滤方法（用户id，策略id，奖品id，规则具体值）
            DefaultTreeFactory.TreeActionEntity logicEntity = logicTreeNode.logic(userId, strategyId, awardId,ruleValue,endDateTime);

            //完成过滤后拿到当前状态
            RuleLogicCheckTypeVO ruleLogicCheckTypeVO = logicEntity.getRuleLogicCheckTypeVO();
            //更新当前需要返回的数据
            strategyAwardData = logicEntity.getStrategyAwardVO();
            log.info("规则树引擎过滤完毕 【{}】treeId:{} node:{} code:{}", ruleTreeVO.getTreeName(), ruleTreeVO.getTreeId(), nextNodeName, ruleLogicCheckTypeVO.getCode());

            //根据当前VO所关联的line查找下一个VO的Name
            nextNodeName = nextNode(ruleLogicCheckTypeVO.getCode(),ruleTreeNodeVO.getTreeNodeLineVOList());
            //拿到对应NodeVO
            ruleTreeNodeVO = treeNodeMap.get(nextNodeName);
        }
        return strategyAwardData;
    }

    /**
     * 根据两个入参返回下一个要执行的节点名称
     * @param checkTypeCode  当前过滤状态
     * @param treeNodeLineVOList 相邻的节点
     * @return 下一个到达的节点名称
     */
    public String nextNode(String checkTypeCode, List<RuleTreeNodeLineVO> treeNodeLineVOList){
        //如果某个VO节点没有与line关联的节点，直接返回
        if (null == treeNodeLineVOList || treeNodeLineVOList.isEmpty()){
            return null;
        }


        for (RuleTreeNodeLineVO nodeLine : treeNodeLineVOList) {
            //使用decisionLogic() 查看是否可以到达
            if (decisionLogic(checkTypeCode,nodeLine)){
                //返回要到达的节点名称
                return nodeLine.getRuleNodeTo();
            }
        }
        //已经没有可以执行的节点直接返回null，调用方才可以跳出循环结束规则树的执行
        return null;
    }

    /**
     * 根据node_line的比较条件，再结合当前节点的状态码进行判别是否是能到达下一个节点
     * @param checkTypeCode 当前执行结果的状态码
     * @param nodeLine nodeLine实例VO
     * @return 是否可以到达
     */
    public boolean decisionLogic(String checkTypeCode, RuleTreeNodeLineVO nodeLine) {
        switch (nodeLine.getRuleLimitType()) {
            case EQUAL:
                //比较当前节点执行完后的状态（ALLOW / TAKE_OVER ）    和所相邻的line的状态码
                return checkTypeCode.equals(nodeLine.getRuleLimitValue().getCode());
            // 以下规则暂时不需要实现
            case GT:
            case LT:
            case GE:
            case LE:
            default:
                return false;
        }
    }

}
